#include "LeakyReLUBPNetwork.hpp"
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <algorithm>
#include <fstream>

using std::string;
using std::cin;
using std::cout;
using std::getline;
using std::vector;
using std::stringstream;
using std::ifstream;

// 去除字符串前后空格
#define trim(s) do{\
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch){\
return !std::isspace(ch);\
}));\
s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch){\
return !std::isspace(ch);\
}).base(), s.end());\
}while(0)

// 提取括号内内容
#define load_content(post, content) do{\
content.clear();\
const char* ptr = input.c_str() + post;\
for(; *ptr != '\0' && *ptr != ')'; ++ptr){\
content += *ptr;\
}\
}while(0)

// 分割字符串为参数列表
vector<string> split_params(const string& s) {
	vector<string> params;
	stringstream ss(s);
	string param;
	while(getline(ss, param, ',')) {
		trim(param);
		if(!param.empty()) params.push_back(param);
	}
	return params;
}

// 打印命令提示
#define print_help() do{\
cout << "支持命令:\n";\
cout << "  store(文件名) - 保存模型\n";\
cout << "  load(文件名) - 加载模型\n";\
cout << "  new() - 重建网络(默认2-3-3-1结构)\n";\
cout << "  train(input1,input2,expect,times) - 训练网络\n";\
cout << "  get(input1,input2) - 获取预测结果\n";\
cout << "  exit - 退出程序\n";\
}while(0)

string input, content;
LeakyReLUBPNetwork net({2, 3, 3, 1}, 0.01);

void explain(){
	getline(cin, input);
	
	if(input == "exit") {
		cout << "程序退出\n";
		exit(0);
	}
	else if(input.find("store(") == 0) {
		load_content(6, content);  // 提取"store("后的内容
		if(content.empty()) {
			cout << "错误: 文件名不能为空\n";
			return;
		}
		try {
			net.store(content);
			cout << "模型已保存至: " << content << "\n";
		} catch(const std::exception& e) {
			cout << "保存失败: " << e.what() << "\n";
		}
	}
	else if(input.find("load(") == 0) {
		load_content(5, content);  // 提取"load("后的内容
		if(content.empty()) {
			cout << "错误: 文件名不能为空\n";
			return;
		}
		try {
			net.load(content);
			cout << "模型已从: " << content << " 加载\n";
		} catch(const std::exception& e) {
			cout << "加载失败: " << e.what() << "\n";
		}
	}
	else if(input == "new()") {
		net = LeakyReLUBPNetwork({2, 3, 3, 1}, 0.01);
		cout << "已重建网络(结构: 2-3-3-1, 学习率0.01)\n";
	}
	else if(input.find("train(") == 0) {
		load_content(6, content);  // 提取"train("后的内容
		vector<string> params = split_params(content);
		if(params.size() != 4) {
			cout << "错误: train需4个参数(input1,input2,expect，times)\n";
			return;
		}
		try {
			// 转换参数为数值
			double in1 = stod(params[0]);
			double in2 = stod(params[1]);
			double expect = stod(params[2]);
			long long times= stoll(params[3]);
			// 执行训练
			while(times--){
				net.train({in1, in2}, {expect});
				net.setLearningRate(net.getLearningRate()*0.9);
			}
			cout << "训练完成: input=(" << in1 << "," << in2 << "), expect=" << expect << "\n";
		} catch(const std::invalid_argument&) {
			cout << "错误: 参数必须为数字\n";
		} catch(const std::exception& e) {
			cout << "训练失败: " << e.what() << "\n";
		}
	}
	else if(input.find("get(") == 0) {
		load_content(4, content);  // 提取"get("后的内容
		vector<string> params = split_params(content);
		if(params.size() != 2) {
			cout << "错误: get需2个参数(input1,input2)\n";
			return;
		}
		try {
			// 转换参数为数值
			double in1 = stod(params[0]);
			double in2 = stod(params[1]);
			// 获取预测结果
			vector<double> output = net.get({in1, in2});
			cout << "预测结果: input=(" << in1 << "," << in2 << "), output=" << output[0] << "\n";
		} catch(const std::invalid_argument&) {
			cout << "错误: 参数必须为数字\n";
		} catch(const std::exception& e) {
			cout << "预测失败: " << e.what() << "\n";
		}
	}
	else if(input == "help") {
		print_help();
	}
	else if(input.find("fromf(") == 0) {
		load_content(6, content);  
		if(content.empty()) {
			cout << "错误: 文件名不能为空\n";
			return;
		}
		try {
			//net.store(content);
			//cout << "模型已保存至: " << content << "\n";
			ifstream ifp(content);
			void explain(ifstream &in);
			while(ifp)explain(ifp);
			
		} catch(const std::exception& e) {
			cout << e.what() << "\n";
		}
	}
	else {
		cout << "未知命令! 输入help查看支持的命令\n";
	}
}

void explain(ifstream &in){
	getline(in, input);
	
	if(input == "exit") {
		cout << "程序退出\n";
		exit(0);
	}
	else if(input.find("store(") == 0) {
		load_content(6, content);  // 提取"store("后的内容
		if(content.empty()) {
			cout << "错误: 文件名不能为空\n";
			return;
		}
		try {
			net.store(content);
			cout << "模型已保存至: " << content << "\n";
		} catch(const std::exception& e) {
			cout << "保存失败: " << e.what() << "\n";
		}
	}
	else if(input.find("load(") == 0) {
		load_content(5, content);  // 提取"load("后的内容
		if(content.empty()) {
			cout << "错误: 文件名不能为空\n";
			return;
		}
		try {
			net.load(content);
			cout << "模型已从: " << content << " 加载\n";
		} catch(const std::exception& e) {
			cout << "加载失败: " << e.what() << "\n";
		}
	}
	else if(input == "new()") {
		net = LeakyReLUBPNetwork({2, 3, 3, 1}, 0.01);
		cout << "已重建网络(结构: 2-3-3-1, 学习率0.01)\n";
	}
	else if(input.find("train(") == 0) {
		load_content(6, content);  // 提取"train("后的内容
		vector<string> params = split_params(content);
		if(params.size() != 4) {
			cout << "错误: train需4个参数(input1,input2,expect，times)\n";
			return;
		}
		try {
			// 转换参数为数值
			double in1 = stod(params[0]);
			double in2 = stod(params[1]);
			double expect = stod(params[2]);
			long long times= stoll(params[3]);
			// 执行训练
			while(times--){
				net.train({in1, in2}, {expect});
				net.setLearningRate(net.getLearningRate()*0.9);
			}
			cout << "训练完成: input=(" << in1 << "," << in2 << "), expect=" << expect << "\n";
		} catch(const std::invalid_argument&) {
			cout << "错误: 参数必须为数字\n";
		} catch(const std::exception& e) {
			cout << "训练失败: " << e.what() << "\n";
		}
	}
	else if(input.find("get(") == 0) {
		load_content(4, content);  // 提取"get("后的内容
		vector<string> params = split_params(content);
		if(params.size() != 2) {
			cout << "错误: get需2个参数(input1,input2)\n";
			return;
		}
		try {
			// 转换参数为数值
			double in1 = stod(params[0]);
			double in2 = stod(params[1]);
			// 获取预测结果
			vector<double> output = net.get({in1, in2});
			cout << "预测结果: input=(" << in1 << "," << in2 << "), output=" << output[0] << "\n";
		} catch(const std::invalid_argument&) {
			cout << "错误: 参数必须为数字\n";
		} catch(const std::exception& e) {
			cout << "预测失败: " << e.what() << "\n";
		}
	}
	else if(input == "help") {
		print_help();
	}
	else if(input.find("fromf(") == 0) {
		load_content(6, content);  
		if(content.empty()) {
			cout << "错误: 文件名不能为空\n";
			return;
		}
		try {
			//net.store(content);
			//cout << "模型已保存至: " << content << "\n";
			ifstream ifp(content);
			while(ifp)explain(ifp);
			
		} catch(const std::exception& e) {
			cout << e.what() << "\n";
		}
	}
	else {
		cout << "未知命令! 输入help查看支持的命令\n";
	}
}

int main() {
	cout << "LeakyReLU BP网络控制台\n";
	print_help();
	
	while(1) {
		cout << "\n输入命令: ";
		explain();
	}
	
	return 0;
}